package com.tdu.spider.biz.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

@Aspect
@Component
public class MethodAspect {
    @Pointcut("execution(public * com.tdu.spider.biz.service.*.*Service(..))")
    private void serviceExecuteMethod() {
    }

    private String toLogMessage(String name, Object... params) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(name).append("::");
        for (int i = 0; i < params.length; i++) {
            stringBuilder.append(params[i]).append("|");
        }
        return stringBuilder.toString();
    }

    private Throwable processServiceException(Logger logger, String msg, Throwable t) {
        return t;
    }

    private static String parseMethodName(String name) {
        if (StringUtils.hasLength(name)) {
            StringBuilder sb = new StringBuilder();
            char[] names = name.toCharArray();
            for (int i = 0; i < names.length; i++) {
                if (names[i] >= 'A' && names[i] <= 'Z') {
                    sb.append(String.format("_%s", names[i]));
                } else {
                    sb.append(String.valueOf(names[i]).toUpperCase());
                }
            }
            return sb.toString();
        }
        return "";
    }

    private static String parseParams(Object[] params) {
        if (params != null && params.length > 0) {
            StringBuilder sb = new StringBuilder();
            for (Object p : params) {
                if (p != null) {
                    sb.append(p.toString());
                    sb.append("|");
                }
            }
            return sb.toString();
        }
        return "";
    }

    @Around("serviceExecuteMethod()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = null;
        Logger logger = LoggerFactory.getLogger(joinPoint.getTarget().getClass());
        String targetClassName = joinPoint.getTarget().getClass().getName();
        String targetClassMethodName = joinPoint.getSignature().getName();
        try {
            result = joinPoint.proceed();
        } catch (Exception e) {
            result = processServiceException(logger, String.format("%s.%s(%s) error",
                    targetClassName, targetClassMethodName, parseParams(joinPoint.getArgs())), e);
            throw e;
        } finally {
            logger.info(toLogMessage(parseMethodName(targetClassMethodName),
                    "cost:" + (System.currentTimeMillis() - start), parseParams(joinPoint.getArgs()),
                    result));
        }
        return result;
    }
}
